﻿using Base.FileCollect;
using Base.FileModel.DB;
using Base.FileModel.UserFile;
using Base.FileModel.UserFileDir;
using Base.FileRemoteModel;
using Base.FileRemoteModel.UserFile.Model;
using Base.FileService.Helper;
using Base.FileService.Interface;
using Base.FileService.Model;
using WeDonekRpc.Helper;
using WeDonekRpc.Modular;

namespace Base.FileService.lmpl
{
    internal class UserFileService : IUserFileService
    {
        private readonly IUserFileCollect _UserFile;
        private readonly IUserFileDirCollect _UserFileDir;
        private readonly IFileConfig _Config;
        public UserFileService ( IUserFileCollect userFile, IFileConfig config, IUserFileDirCollect userFileDir )
        {
            this._Config = config;
            this._UserFile = userFile;
            this._UserFileDir = userFileDir;
        }

        public void SaveSort ( Dictionary<long, int> sort )
        {
            this._UserFile.SaveSort(sort);
        }
        public void Drop ( string dirKey, long linkBizPk, string tag )
        {
            UserFileDirDto dir = this._UserFileDir.GetDir(dirKey);
            long[] ids = this._UserFile.GetIds(dir.Id, linkBizPk, tag);
            if ( ids.IsNull() )
            {
                return;
            }
            this._UserFile.Drop(ids);
        }

        public void Delete ( long fileId, IUserState state )
        {
            UserFileDto file = this._UserFile.GetFile(fileId);
            long empId = state.GetValue<long>("UserId");
            if ( file.UserId != empId || ( !file.OperatePower.IsNull() && !file.OperatePower.IsExists(state.Power.IsExists) ) )
            {
                throw new ErrorException("file.delete.power.error");
            }
            else if ( file.FileStatus == UserFileStatus.起草 )
            {
                this._UserFile.Delete(fileId);
                return;
            }
            else if ( file.FileStatus == UserFileStatus.作废 || file.FileStatus == UserFileStatus.已删除 )
            {
                return;
            }
            this._UserFile.Drop(fileId);
        }


        public DirUpConfig GetUploadConfig ( GetConfigArg arg )
        {
            UserFileDirDto dir = this._UserFileDir.GetDir(arg.DirKey);
            if ( !arg.LinkBizPk.HasValue )
            {
                return new DirUpConfig
                {
                    UpShow = dir.UpShow,
                    Extension = dir.AllowExtension,
                    UpFileSize = dir.AllowUpFileSize,
                    UpImgSet = dir.UpImgSet,
                    ZoneSize = this._Config.ZoneSize
                };
            }
            UserFileBasic[] files = this._UserFile.GetFiles(dir.Id, arg.LinkBizPk.Value, arg.Tag);
            return new DirUpConfig
            {
                Extension = dir.AllowExtension,
                UpShow = dir.UpShow,
                UpFileSize = dir.AllowUpFileSize,
                ZoneSize = this._Config.ZoneSize,
                Files = files.OrderBy(a => a.Sort).ThenBy(a => a.Id).Select(a => new UserFile
                {
                    FileId = a.Id,
                    FileName = a.FileName,
                    FileUri = a.GetFileUri(this._Config)
                }).ToArray()
            };
        }
        public void SaveFile ( long[] fileId, long linkBizPk, long[] dropId )
        {
            this._UserFile.SaveFile(fileId, linkBizPk, dropId);
        }
        public void SaveFile ( long fileId, long linkBizPk, long[] dropId )
        {
            UserFileDto file = this._UserFile.GetFile(fileId);
            this._UserFile.SaveFile(file, linkBizPk, dropId);
        }
        public void Drop ( long[] fileId )
        {
            this._UserFile.Drop(fileId);
        }
        public void Drop ( long fileId )
        {
            this._UserFile.Drop(fileId);
        }

        public void Drop ( string[] dirKey, long[] linkBizPk )
        {
            long[] dirId = this._UserFileDir.GetDirId(dirKey);
            long[] ids = this._UserFile.GetIds(dirId, linkBizPk);
            if ( ids.IsNull() )
            {
                return;
            }
            this._UserFile.Drop(ids);
        }

        public UserFile GetUserFile ( long fileId )
        {
            UserFileBasic file = this._UserFile.GetFileBasic(fileId);
            return new UserFile
            {
                FileId = file.Id,
                FileName = file.FileName,
                Extension = file.Extension,
                FileUri = file.GetFileUri(this._Config)
            };
        }

        public UserFileData[] GetFiles ( List<long> linkPk, string[] linkType, string[] tag )
        {
            Dictionary<long, string> dirs = this._UserFileDir.GetDirs(linkType);
            UserFileModel[] files = this._UserFile.GetFiles(linkPk, dirs.Keys.ToArray());
            if ( files.IsNull() )
            {
                return null;
            }
            if ( !tag.IsNull() )
            {
                files = files.FindAll(a => a.Tag.IsNull() || tag.Contains(a.Tag));
            }
            return files.ConvertAll(a => new UserFileData
            {
                FileId = a.Id,
                LinkBizPk = a.LinkBizPk.Value,
                DirKey = dirs[a.UserDirId],
                Tag = a.Tag,
                FileUri = a.GetFileUri(this._Config),
                FileName = a.FileName
            });
        }
        public UserFile[] GetFiles ( long linkPk, string linkType, string tag )
        {
            long dirId = this._UserFileDir.GetDirId(linkType);
            UserFileBasic[] files = this._UserFile.GetFiles(dirId, linkPk, tag);
            if ( files.IsNull() )
            {
                return null;
            }
            return files.ConvertAll(a => new UserFile
            {
                FileId = a.Id,
                FileUri = a.GetFileUri(this._Config),
                FileName = a.FileName,
                Extension = a.Extension
            });
        }

        public UserFile Copy ( CopyFileArg arg, IUserState state )
        {
            UserFileDto file = this._UserFile.GetFile(arg.FileId);
            if ( file.Power == FilePower.指定权限 )
            {
                if ( !state.CheckPower(file.OperatePower) )
                {
                    throw new ErrorException("accredit.no.power");
                }
            }
            else if ( file.Power == FilePower.私有 && file.UserId != state.ToEmpId() )
            {
                throw new ErrorException("accredit.no.power");
            }
            long empId = state.ToEmpId();
            string userType = state.ToUserType();
            UserFileDirDto dir = this._UserFileDir.GetDir(arg.DirKey);
            if ( arg.LinkBizPk.HasValue )
            {
                UserFileBasic t = this._UserFile.FindTempFile(new UserFileGet
                {
                    FileId = file.FileId,
                    UserDirId = dir.Id,
                    LinkPk = arg.LinkBizPk.Value,
                    Tag = arg.Tag,
                    UserId = empId,
                    UserType = userType
                });
                if ( t != null )
                {
                    return new UserFile
                    {
                        FileId = t.Id,
                        FileUri = t.GetFileUri(this._Config),
                        FileName = t.FileName,
                    };
                }
            }
            UserFileAdd add = new UserFileAdd
            {
                UserId = empId,
                UserType = userType,
                UserDirId = dir.Id,
                Power = dir.Power,
                PowerCode = dir.ReadPower,
                LinkBizPk = arg.LinkBizPk,
                Tag = arg.Tag,
                Extension = file.Extension,
                OperatePower = dir.UpPower,
                IsSave = false,
                FileName = file.FileName,
                FileType = file.Extension.GetFileType(),
                FileId = file.FileId
            };
            DBUserFileList userFile = this._UserFile.Add(add);
            return new UserFile
            {
                FileId = userFile.Id,
                FileUri = userFile.GetFileUri(this._Config),
                FileName = userFile.FileName,
            };
        }

        public UserFileStream GetStream ( long fileId )
        {
            UserFileDto t = this._UserFile.GetFile(fileId);
            FileInfo file = new FileInfo(t.FilePath);
            if ( !file.Exists )
            {
                throw new ErrorException("file.no.exists");
            }
            return new UserFileStream
            {
                FileName = t.FileName,
                FileUri = t.GetFileUri(this._Config),
                Stream = file.ReadBytes()
            };
        }

        public void Restore ( long[] fileId )
        {
            this._UserFile.Restore(fileId);
        }

        public void ToVoid ( long[] fileId )
        {
            this._UserFile.ToVoid(fileId);
        }

        public UserFileDatum[] GetFiles ( UserFileGetParam param )
        {
            long[] dir = this._UserFileDir.GetDirId(param.LinkType);
            return this._UserFile.GetFiles<UserFileDatum>(new UserFileGetArg
            {
                Extension = param.Extension,
                LinkPk = param.LinkPk,
                Tag = param.Tag,
                UserDirId = dir
            });
        }

        public void Copy ( UserFileCopy[] files )
        {
            List<long> ids = new List<long>();
            List<string> dirKey = new List<string>();
            files.ForEach(c =>
            {
                dirKey.Add(c.DirKey);
                ids.AddRange(c.FileId);
            });
            Dictionary<string, UserFileDirDto> fileDir = this._UserFileDir.Gets(dirKey);
            UserFileDto[] list = this._UserFile.Gets(ids);
            List<UserFileAdd> adds = new List<UserFileAdd>();
            files.ForEach(a =>
            {
                UserFileDirDto dir = fileDir[a.DirKey];
                a.FileId.ForEach(c =>
                {
                    UserFileDto file = list.Find(b => b.Id == c);
                    adds.Add(new UserFileAdd
                    {
                        UserId = file.UserId,
                        UserType = file.UserType,
                        UserDirId = dir.Id,
                        Power = dir.Power,
                        PowerCode = dir.ReadPower,
                        LinkBizPk = a.LinkPk,
                        Tag = a.Tag,
                        Extension = file.Extension,
                        OperatePower = dir.UpPower,
                        IsSave = true,
                        FileName = file.FileName,
                        FileType = file.Extension.GetFileType(),
                        FileId = file.FileId
                    });
                });
            });
            this._UserFile.Adds(adds);
        }
    }
}
